package avicit.bdp.dds.api.controller;

import avicit.bdp.common.dto.query.dds.ExecutorQuery;
import avicit.bdp.common.dto.request.dds.ProcessSchedulerDto;
import avicit.bdp.common.utils.DateUtils;
import avicit.bdp.dds.dispatch.enums.CommandType;
import avicit.bdp.dds.dispatch.enums.ExecutionStatus;
import avicit.bdp.dds.dispatch.enums.FailureStrategy;
import avicit.bdp.dds.dispatch.enums.Priority;
import avicit.bdp.dds.dispatch.enums.RunMode;
import avicit.bdp.dds.dispatch.enums.TaskDependType;
import avicit.bdp.dds.dispatch.enums.WarningType;
import avicit.bdp.dds.ApiApplicationServer;
import avicit.bdp.dds.api.service.ProcessInstanceService;
import avicit.bdp.dds.dao.entity.ProcessDefinition;
import avicit.bdp.dds.dao.entity.ProcessInstance;
import avicit.bdp.dds.dao.mapper.ProcessDefinitionMapper;
import avicit.bdp.dds.dao.mapper.ProcessInstanceMapper;
import avicit.bdp.dds.service.quartz.cron.CronUtils;
import avicit.platform6.core.rest.msg.ResponseMsg;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;
import java.util.List;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2020-06-24 14:54
 * @类说明：ProcessDefinitionRest
 * @修改记录：
 * @注意事项：
 */
@RunWith(SpringRunner.class)
@ComponentScan(basePackages = {"avicit.bdp.dds", "avicit.bdp.common"})
@SpringBootTest(classes= {ApiApplicationServer.class})
public class DDSProcessTest {
    @Autowired
    ProcessInstanceRest processInstanceRest;

    @Autowired
    ExecutorRest executorRest;

    @Autowired
    ProcessDefinitionRest processDefinitionRest;

    @Autowired
    ProcessDefinitionMapper processDefinitionMapper;

    @Autowired
    private ProcessInstanceMapper processInstanceMapper;

    @Autowired
    private ProcessInstanceService processInstanceService;

    @Autowired
    private SchedulerRest schedulerRest;

    private static ProcessDefinition processDefeCreate;

    private static ProcessSchedulerDto schedule;


    /**
     * 所有用例执行前准备工作
     */
    @BeforeClass
    public static void init() {
        // step1:构造流程定义参数;

        processDefeCreate = new ProcessDefinition();
        processDefeCreate.setId("828081857409c289017409c289802223");
        processDefeCreate.setName("算法库测试1");
        processDefeCreate.setReleaseState(0);
        processDefeCreate.setTypeId("test");
        //processDefeCreate.setProjectId("828081857409c289017409c289801111");
        processDefeCreate.setProjectId("4028809874d631770174d7b07a6d0040");
        processDefeCreate.setType(2);
        processDefeCreate.setDatasourceId("spark");
        processDefeCreate.setProcessDefinitionJson("{\"globalParams\":[],\"tasks\":[{\"type\":\"ALGORITHM\",\"id\":\"tasks-9682\",\"name\":\"测试algorithm\",\"params\":{\"type\":0,\"nodeId\":\"10\",\"inputType\":0,\"inputDatasourceId\":\"402880a4742f5b7e01742f5b7e7d0000\",\"inputTableId\":\"402880a4742ed37a01742ed37a1a0000\",\"inputTableName\":\"\",\"inputParams\":{\"id\":\"testId\"},\"outputType\":\"0\",\"outputDatasourceId\":\"402880a4742f5b7e01742f5b7e7d0000\",\"outputTableId\":\"402880a4742ed37a01742ed37a1a0000\",\"outputTableName\":\"\",\"outputParams\":{ \"testname\":\"name\"}},\"description\":\"1\",\"runFlag\":\"NORMAL\",\"conditionResult\":{\"successNode\":[\"\"],\"failedNode\":[\"\"]},\"dependence\":{},\"maxRetryTimes\":\"0\",\"retryInterval\":\"1\",\"timeout\":{\"strategy\":\"\",\"interval\":null,\"enable\":false},\"taskInstancePriority\":\"MEDIUM\",\"workerGroup\":\"default\",\"preTasks\":[]}],\"tenantId\":1,\"timeout\":0}");
        processDefeCreate.setLocations("{\"tasks-9682\":{\"name\":\"测试algorithm\",\"targetarr\":\"\",\"nodenumber\":\"0\",\"x\":392,\"y\":160}}");

        schedule = new ProcessSchedulerDto();
        schedule.setId("828081857409c289017409c289803002");
        schedule.setProcessDefinitionId(processDefeCreate.getId());
        schedule.setStartTime(DateUtils.getCurrentDate());
        schedule.setEndTime(DateUtils.getEndOfDay(schedule.getStartTime()));
        schedule.setProcessInstancePriority(2);
        schedule.setCrontab(CronUtils.getCron(new Date( System.currentTimeMillis() + 3 * 1000L)));//3秒后执行
        schedule.setFailureStrategy(FailureStrategy.END.getCode());

    }

    /**
     * 单个测试用例运行前准备工作
     */
    @Before
    public void setUp() {

    }

    /**
     * 单个测试用例运行后销毁工作
     */
    @After
    public void tearDown() {
        // TODO:
    }

    /**
     * 所有用例执行完成后准备工作
     */
    @AfterClass
    public static void destory() {
        // TODO:
    }

    /**
     * 预先创建流程定义；
     * @throws RuntimeException
     */
    public void createProcessDefe() throws RuntimeException{
        try {
            ResponseMsg<String> responseMsg = processDefinitionRest.createProcessDefinition(processDefeCreate);
            if (!"200".equals(responseMsg.getRetCode())) {
                System.out.println("Create processDefe failed.");
                throw new RuntimeException("Create processDefe failed.");
            }

            ResponseMsg<Boolean> scheduleResponseMsg =  schedulerRest.createSchedule(schedule);
            if (!"200".equals(scheduleResponseMsg.getRetCode())) {
                System.out.println("Create schedule failed.");
                throw new RuntimeException("Create schedule failed.");
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 预先上线流程定义；
     * @throws RuntimeException
     */
    public void releaseProcessDefe(int releaseState) throws RuntimeException{
        try {
            ResponseMsg<Boolean> responseMsg =
                    processDefinitionRest.releaseProcessDefinition(processDefeCreate.getId(), releaseState);

            if (!"200".equals(responseMsg.getRetCode())) {
                System.out.println("Release processDefe failed.");
                throw new RuntimeException("Release processDefe failed.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 启动流程定义；
     */
    public void startProcIns() throws Exception {
        String processDefinitionId = processDefeCreate.getId();
        String scheduleTime = "";
        FailureStrategy failureStrategy = FailureStrategy.END;
        String startNodeList = null;
        TaskDependType taskDependType = TaskDependType.TASK_POST;
        CommandType execType = CommandType.START_CURRENT_TASK_PROCESS;
        WarningType warningType = WarningType.FAILURE;
        String warningUserIds = "avicit2015";
        RunMode runMode = RunMode.RUN_MODE_SERIAL;
        Priority processInstancePriority = Priority.MEDIUM;
        String workerGroup = null;
        Integer timeout = null;

        ExecutorQuery executorQuery = new ExecutorQuery();
        // todo set value
        executorQuery.setProcessDefinitionId(processDefeCreate.getId());
        executorQuery.setFailureStrategy(FailureStrategy.END.getCode());
        executorQuery.setWarningUserIds(warningUserIds);
        ResponseMsg<Boolean> responseMsg = executorRest.startProcessInstance(executorQuery);

        Assert.assertEquals("200",responseMsg.getRetCode());
    }

    /**
     * 用例执行完毕后删除流程定义；
     * @throws RuntimeException
     */
    public void deleteProcessDefe() throws RuntimeException{
        try {
            ResponseMsg<Boolean> responseMsg = processDefinitionRest.deleteProcessDefinitionById(processDefeCreate.getId());
            if (!"200".equals(responseMsg.getRetCode())) {
                System.out.println("Delete processDefe failed.");
                throw new RuntimeException("Delete processDefe failed.");
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 用例执行完毕后删除流程定义；
     * @throws RuntimeException
     */
    public void deleteTestProcessDefe() throws RuntimeException{
        try {
            ResponseMsg<Boolean> responseMsg = processDefinitionRest.deleteProcessDefinitionById(processDefeCreate.getId());
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    /**
     * 用例执行完后删除流程实例；
     * @throws RuntimeException
     */
    public void deleteProcessInstance() throws RuntimeException{
        try {
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }

            for (ProcessInstance processInstance : processInstances) {
                int ret = processInstanceMapper.deleteByPrimaryKey(processInstance.getId());
                if (ret <= 0) {
                    throw new RuntimeException("Delete processInstance " + processInstance.getId() + " failed.");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    /**
     * 用例执行完后删除流程实例；
     * @throws RuntimeException
     */
    public void deleteTestProcessInstance() throws RuntimeException{
        try {
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);

            for (ProcessInstance processInstance : processInstances) {
                int ret = processInstanceMapper.deleteByPrimaryKey(processInstance.getId());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /**
     * 根据流程实例ID查询
     */
    @Test
    public void testQueryProcessInstanceById_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义（4）查询流程实例
            // step1_1:创建流程定义、发布流程定义;
            createProcessDefe();
            //流程启用
            //releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();

            // step1_3:查询流程实例
            //流程启用后，3秒自动执行流程任务
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待4s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }
            ProcessInstance processInstance = processInstances.get(0);

            // step2:执行阶段
            ResponseMsg<ProcessInstance> responseMsg = processInstanceRest.queryProcessInstanceById(null, processInstance.getId());

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
            ProcessInstance rsp = responseMsg.getResponseBody();
            Assert.assertEquals(rsp.getName().equals(processInstance.getName()), true);

            //判断流程实例执行情况
            ProcessInstance pi = processInstanceService.selectByPrimaryKey(processInstance.getId());
            ExecutionStatus status = ExecutionStatus.of(pi.getState());
            while(!status.typeIsFinished()){
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                pi = processInstanceService.selectByPrimaryKey(processInstance.getId());
                status = ExecutionStatus.of(pi.getState());
                System.out.println(status);
            }


        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例（3）删除流程实例
            releaseProcessDefe(0);
            deleteTestProcessInstance();
            deleteTestProcessDefe();
        }
    }



}
